/*
 *  Class name: MatchManagedBean.java
 *  Version: 1.0
 *  Date: 2.3.2014
 */
package cz.muni.fi.pa165.soccergamesarchive.managedbeans.entity;

import cz.muni.fi.pa165.soccergamesarchive.businesslayer.dtos.SoccerMatchDTO;
import cz.muni.fi.pa165.soccergamesarchive.businesslayer.dtos.SoccerMatchDetailDTO;
import cz.muni.fi.pa165.soccergamesarchive.businesslayer.dtos.TeamDTO;
import cz.muni.fi.pa165.soccergamesarchive.businesslayer.services.SoccerMatchServiceBeanLocal;
import cz.muni.fi.pa165.soccergamesarchive.businesslayer.services.TeamServiceBeanLocal;
import cz.muni.fi.pa165.soccergamesarchive.datamodels.entity.TeamDataModel;
import cz.muni.fi.pa165.soccergamesarchive.managedbeans.application.ActionState;
import cz.muni.fi.pa165.soccergamesarchive.managedbeans.application.DialogChooserListenable;
import cz.muni.fi.pa165.soccergamesarchive.managedbeans.application.NavigationMapper;
import cz.muni.fi.pa165.soccergamesarchive.managedbeans.application.NavigationMenuBean;
import cz.muni.fi.pa165.soccergamesarchive.managedbeans.entity.handlers.table.SoccerMatchArrangeableTableHandler;
import cz.muni.fi.pa165.soccergamesarchive.utils.SoccerMatchHandler;
import java.io.Serializable;
import java.time.format.FormatStyle;
import java.util.Map;
import java.util.Objects;
import java.util.ResourceBundle;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;

import static cz.muni.fi.pa165.soccergamesarchive.utils.LabelTextHandler.getActionDescriptionText;
import static cz.muni.fi.pa165.soccergamesarchive.utils.LabelTextHandler.getFullActionDescriptionText;
import static cz.muni.fi.pa165.soccergamesarchive.utils.SoccerMatchHandler.createMatchDetail;
import static java.time.chrono.Chronology.ofLocale;
import static java.time.format.DateTimeFormatterBuilder.getLocalizedDateTimePattern;
import static java.util.Locale.getDefault;
import static javax.faces.context.FacesContext.getCurrentInstance;

/**
 *
 * @author Michal Ďuriš
 */
@Named(value = "matchManagedBean")
@SessionScoped
public class MatchManagedBean implements Serializable, DialogChooserListenable {

    private static final long serialVersionUID = 1L;

    private static final String MATCH_DATE_PATTERN;

    static {
        MATCH_DATE_PATTERN = getLocalizedDateTimePattern(FormatStyle.LONG,
                FormatStyle.SHORT,
                ofLocale(getDefault()),
                getDefault());
    }

    @EJB
    private SoccerMatchServiceBeanLocal matchService;

    @EJB
    private TeamServiceBeanLocal teamService;

    @Inject
    private GoalManagedBean goalManagedBean;

    @Inject
    private SoccerMatchArrangeableTableHandler tableHandler;

    @Inject
    private NavigationMenuBean menuBean;

    private TeamDataModel teamDataModel;

    private SoccerMatchDTO currentlyManagedMatch;

    private SoccerMatchDetailDTO currentlyDetailedMatch;

    private ActionState currentState;

    /**
     * Creates a new instance of MatchManagedBean
     */
    public MatchManagedBean() {
    }

    @PostConstruct
    public void init() {

        teamDataModel = new TeamDataModel(teamService);
        teamDataModel.getFilterMap().put("name", "");
        teamDataModel.getFilterMap().put("bannedTeam", null);

        currentlyManagedMatch = new SoccerMatchDTO();
    }

    public String getMatchDatePattern() {
        return MATCH_DATE_PATTERN;
    }

    public GoalManagedBean getGoalManagedBean() {
        return goalManagedBean;
    }

    public SoccerMatchArrangeableTableHandler getTableHandler() {
        return tableHandler;
    }

    public SoccerMatchDTO getCurrentlyManagedMatch() {
        return currentlyManagedMatch;
    }

    public void setCurrentlyManagedMatch(SoccerMatchDTO currentlyManagedMatch) {
        this.currentlyManagedMatch = currentlyManagedMatch;
    }

    public SoccerMatchDetailDTO getCurrentlyDetailedMatch() {
        return currentlyDetailedMatch;
    }

    public void setCurrentlyDetailedMatch(
            SoccerMatchDetailDTO currentlyDetailedMatch) {
        this.currentlyDetailedMatch = currentlyDetailedMatch;
    }

    public ActionState getCurrentState() {
        return currentState;
    }

    public void setCurrentState(ActionState currentState) {
        this.currentState = currentState;
    }

    public String getEditorPanelTitle() {

        String title;

        try {
            title = getFullActionDescriptionText(currentState,
                    NavigationMapper.MATCH_MODULE);
        } catch (IllegalStateException e) {
            title = "ERROR";
            //TODO: SOME ERROR STATE DIALOG WINDOW
        }

        return title;
    }

    public String getEditorButtonLabel() {

        String label;

        try {
            label = getActionDescriptionText(currentState);
        } catch (IllegalStateException e) {
            label = "ERROR";
            //TODO: SOME ERROR STATE DIALOG WINDOW
        }

        return label;
    }

    @Override
    public Object getDataModel() {
        return teamDataModel;
    }

    @Override
    public Map<String, Object> getFilterMap() {
        return teamDataModel.getFilterMap();
    }

    @Override
    public void storeResult(String resultName, Object result) {

        if (result != null && result instanceof TeamDTO) {

            TeamDTO team = (TeamDTO) result;

            switch (resultName) {
                case "homeTeam":
                    currentlyManagedMatch.setHomeTeam(team);
                    goalManagedBean.getFilterMap().put("homeTeam", team.getId());
                    break;
                case "awayTeam":
                    currentlyManagedMatch.setAwayTeam(team);
                    goalManagedBean.getFilterMap().put("awayTeam", team.getId());
                    break;
                default:
                    System.err.println(
                            "UNABLE TO RECOGNIZE RESULT DESTINATION NAME "
                            + "IN CLASS " + getClass().getName());
                    return;
                //TODO: LOGGER
            }

            if (currentlyManagedMatch.getGoals() != null
                && !currentlyManagedMatch
                    .getGoals().isEmpty()) {

                goalManagedBean.updateGoalList();
            }
        }

        teamDataModel.getFilterMap().put("name", "");
    }

    public void setChooserRestriction(String restrictionValue) {

        Long bannedTeamID = null;

        switch (restrictionValue) {
            case "homeTeam":
                bannedTeamID = currentlyManagedMatch.getAwayTeam().getId();
                break;
            case "awayTeam":
                bannedTeamID = currentlyManagedMatch.getHomeTeam().getId();
                break;
            default:
                if (restrictionValue.contains("player")) {
                    break;
                }

                System.err.println("UNRECOGNIZED RESTRICTION VALUE in class: "
                                   + getClass().getName());
            //TODO: LOGGER
        }

        teamDataModel.getFilterMap().put("bannedTeam", bannedTeamID);
    }

    public String processActionAndRedirect(ActionState state) {

        currentlyDetailedMatch = null;

        switch (state) {
            case ADD:
                currentState = state;
                currentlyManagedMatch = new SoccerMatchDTO();

                teamDataModel.getFilterMap().put("name", "");
                teamDataModel.getFilterMap().put("bannedTeam", null);

                goalManagedBean.getFilterMap().put("lastName", "");
                goalManagedBean.getFilterMap().put("homeTeam", null);
                goalManagedBean.getFilterMap().put("awayTeam", null);

                return menuBean.goToLocation(NavigationMapper.MATCH_MODULE,
                        NavigationMapper.ADD_SECTION);
            case EDIT:
                currentState = state;

                teamDataModel.getFilterMap().put("name", "");
                teamDataModel.getFilterMap().put("bannedTeam", null);

                goalManagedBean.getFilterMap().put("lastName", "");
                goalManagedBean.getFilterMap().put("homeTeam",
                        currentlyManagedMatch.getHomeTeam().getId());
                goalManagedBean.getFilterMap().put("awayTeam",
                        currentlyManagedMatch.getAwayTeam().getId());

                return menuBean.goToLocation(NavigationMapper.MATCH_MODULE,
                        NavigationMapper.EDIT_SECTION);
            case VIEW:
                currentState = state;
                currentlyManagedMatch = new SoccerMatchDTO();
                
                return menuBean.goToLocation(NavigationMapper.MATCH_MODULE,
                        NavigationMapper.VIEW_SECTION);
            default:
                System.err.println("UNHANDLED ACTION = NO REDIRECT");
        }

        return "";
    }

    public String handleAction() {

        switch (currentState) {
            case ADD:
                if (validateMatch() && addMatch()) {
                    
                    return menuBean.goToLocation(NavigationMapper.MATCH_MODULE,
                            NavigationMapper.VIEW_SECTION);
                }
                break;
            case EDIT:
                if (validateMatch() && changeMatch()) {
                    
                    return menuBean.goToLocation(NavigationMapper.MATCH_MODULE,
                            NavigationMapper.VIEW_SECTION);
                }
                break;
            case DELETE:
                deleteMatch();
                break;
            default:
                System.err.println("UNHANDLED ACTION");
        }

        return "";
    }

    private boolean validateMatch() {

        FacesContext facesContext = getCurrentInstance();

        ResourceBundle bundle = facesContext.getApplication().getResourceBundle(
                facesContext, "bundle");

        FacesMessage inputRequiredMessage = new FacesMessage(
                FacesMessage.SEVERITY_ERROR, bundle.getString(
                        "requiredValidationMessage"), bundle.getString(
                        "requiredValidationMessage"));

        boolean errorFlag = false;

        if (currentlyManagedMatch.getHomeTeam().getId() == null) {

            errorFlag = true;
            facesContext.addMessage("matchEditorForm:homeTeam",
                    inputRequiredMessage);
        }

        if (currentlyManagedMatch.getAwayTeam().getId() == null) {

            errorFlag = true;
            facesContext.addMessage("matchEditorForm:awayTeam",
                    inputRequiredMessage);
        }

        return goalManagedBean.validateGoals(inputRequiredMessage) && !errorFlag;
    }

    private boolean addMatch() {

        try {
            matchService.addSoccerMatch(currentlyManagedMatch);
        } catch (RuntimeException e) {
            return false;
        }

        return true;
    }

    private boolean changeMatch() {
        try {
            matchService.changeSoccerMatch(currentlyManagedMatch);
        } catch (RuntimeException e) {
            return false;
        }
        return true;
    }

    private boolean deleteMatch() {
        try {
            matchService.deleteSoccerMatch(currentlyManagedMatch);

            if (currentlyDetailedMatch != null
                && Objects.equals(currentlyManagedMatch.getId(),
                            currentlyDetailedMatch.getId())) {

                currentlyDetailedMatch = null;
            }

        } catch (RuntimeException e) {
            return false;
        }
        return true;
    }

    public String getSoccerMatchScore(SoccerMatchDTO soccerMatch) {

        String score = SoccerMatchHandler.getSoccerMatchScore(soccerMatch);

        return score == null ? "ERROR" : score;
    }

    public void processShowDetailMatchRequest(Long key) {

        if (currentlyDetailedMatch != null
            && Objects.equals(currentlyDetailedMatch.getId(), key)) {
            currentlyDetailedMatch = null;
        } else {
            currentlyDetailedMatch = createMatchDetail(
                    matchService.getSoccerMatchById(key));
        }
    }

}
